/*
 * Copyright 2014, NuzoweR@Schneefeuer <nuzower@gmail.com>.
 * The Settlers Online - Combat Simulator (tsosim).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef GARRISON_H_
#define GARRISON_H_

#include "Units.h"

#include <list>
#include <vector>

class Statistics;

class Garrison 
{
public:
	// don't use this
	Garrison() {};

	// copy constructor
	Garrison(const Garrison&);

	struct Group 
	{
		Group() : unit(NULL), number(0), number_after_attack(0), number_left_to_attack(0), hitpoints(), damage_left(0) {};
		const Unit* unit; 
		int number;
		int number_after_attack;   // when defending
		int number_left_to_attack; // when attacking
		std::vector<int> hitpoints;
		int damage_left;           // if last unit still has splash damage left, but the opposing group is no more,
		                           // then the remaining damage must be applied to the next group
	};

	typedef std::map<const Unit*,Group> UnitsMap_t;
	typedef std::list<const Unit*>	    UnitOrder_t;
	typedef std::list<Group*>           GroupOrder_t;


	static Garrison* create(std::string const& id, int tower_bonus);
	static Garrison* get(std::string const& id);

	std::string const& name()          const { return m_name;        }
	int                getTowerBonus() const { return m_tower_bonus; }

	bool add_units(const Unit* unit, int number);


	static bool sort_by_hitpoints(const Group* g1, const Group* g2);
	static bool sort_by_attack_id(const Group* g1, const Group* g2);
	static bool sort_by_non_default_unit_order(const Group* g1, const Group* g2); // not yet implemented


	bool set_unit_order(UnitOrder_t const& order, std::string& error);
	void setTowerBonus(int bonus)   { m_tower_bonus = bonus; }

	GroupOrder_t get_defend_list_weakest();

	GroupOrder_t get_defend_list_normal();

	GroupOrder_t get_attack_list_by_initiative(Initiative::EInitiative type);

	enum STAT_UPDATE{ NORMAL, MIN, MAX };

	void init_stats  (Statistics* stats);
	void update_stats(Statistics* stats, STAT_UPDATE su);


	/**
	 * set number of units to the number left units after a fight.
	 * couldn't have set it immediately, because need original number of units for counter-attack
	 */
	void update_garrison_after_initiative();

	void update_garrison_after_combat();

	int  has_units_with_hitpoints() const;

private:

	void set_name(std::string name) { m_name = name; }

	void update_group_order();
	void update_group_order(GroupOrder_t& group, UnitOrder_t& unordered_units);

	std::string     m_name;

	int             m_tower_bonus;

	// actual units (with hitpoints etc.)
	UnitsMap_t      m_units;

	// nonstandard unit order
	UnitOrder_t     m_unit_order;

	// group order : computed from standard or non-standard unit order
	GroupOrder_t    m_group_order;
};

#endif // GARRISON_H_
